#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MCP Calculator Server - Configuration Management

配置管理模块，支持环境变量和配置文件
"""

import os
import json
from typing import Dict, Any, Optional
from dataclasses import dataclass, asdict
from pathlib import Path

@dataclass
class ServerConfig:
    """服务器配置"""
    name: str = "Enhanced Calculator Server"
    version: str = "2.0.0"
    description: str = "Enhanced MCP Calculator with advanced mathematical functions"
    transport: str = "stdio"
    host: str = "localhost"
    port: int = 8000
    debug: bool = False
    log_level: str = "INFO"
    max_cache_size: int = 1000
    precision: int = 50
    enable_metrics: bool = True
    enable_history: bool = True
    max_history_size: int = 1000

@dataclass
class SecurityConfig:
    """安全配置"""
    max_expression_length: int = 1000
    max_recursion_depth: int = 100
    timeout_seconds: int = 30
    enable_function_whitelist: bool = True
    allowed_functions: list = None
    blocked_patterns: list = None
    safe_mode: bool = True
    
    def __post_init__(self):
        if self.allowed_functions is None:
            self.allowed_functions = [
                'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
                'sinh', 'cosh', 'tanh', 'log', 'log10', 'log2',
                'exp', 'sqrt', 'abs', 'ceil', 'floor', 'round',
                'factorial', 'degrees', 'radians'
            ]
        
        if self.blocked_patterns is None:
            self.blocked_patterns = [
                r'__.*__',
                r'import\s+',
                r'exec\s*\(',
                r'eval\s*\(',
                r'open\s*\(',
                r'file\s*\(',
                r'input\s*\(',
                r'print\s*\(',
                r'os\.',
                r'sys\.',
            ]

@dataclass
class LoggingConfig:
    """日志配置"""
    level: str = "INFO"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    file_path: Optional[str] = None
    max_file_size: int = 10 * 1024 * 1024  # 10MB
    backup_count: int = 5
    enable_console: bool = True
    enable_file: bool = False

class ConfigManager:
    """配置管理器"""
    
    def __init__(self, config_file: Optional[str] = None):
        self.config_file = config_file or self._find_config_file()
        self.server_config = ServerConfig()
        self.security_config = SecurityConfig()
        self.logging_config = LoggingConfig()
        
        self._load_config()
        self._load_env_vars()
    
    def _find_config_file(self) -> Optional[str]:
        """查找配置文件"""
        possible_paths = [
            "config.yaml",
            "config.json",
            "settings.yaml",
            "settings.json",
            os.path.join(os.path.dirname(__file__), "..", "config.yaml"),
            os.path.join(os.path.dirname(__file__), "..", "config.json"),
        ]
        
        for path in possible_paths:
            if os.path.exists(path):
                return path
        
        return None
    
    def _load_config(self):
        """从配置文件加载配置"""
        if not self.config_file or not os.path.exists(self.config_file):
            return
        
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                if self.config_file.endswith('.json'):
                    config_data = json.load(f)
                elif self.config_file.endswith(('.yaml', '.yml')):
                    import yaml
                    config_data = yaml.safe_load(f)
                else:
                    return
            
            # 更新服务器配置
            if 'server' in config_data:
                for key, value in config_data['server'].items():
                    if hasattr(self.server_config, key):
                        setattr(self.server_config, key, value)
            
            # 更新安全配置
            if 'security' in config_data:
                for key, value in config_data['security'].items():
                    if hasattr(self.security_config, key):
                        setattr(self.security_config, key, value)
            
            # 更新日志配置
            if 'logging' in config_data:
                for key, value in config_data['logging'].items():
                    if hasattr(self.logging_config, key):
                        setattr(self.logging_config, key, value)
                        
        except Exception as e:
            print(f"加载配置文件失败: {e}")
    
    def _load_env_vars(self):
        """从环境变量加载配置"""
        # 服务器配置
        env_mappings = {
            'CALC_SERVER_NAME': ('server_config', 'name'),
            'CALC_SERVER_VERSION': ('server_config', 'version'),
            'CALC_SERVER_DEBUG': ('server_config', 'debug'),
            'CALC_SERVER_LOG_LEVEL': ('server_config', 'log_level'),
            'CALC_SERVER_HOST': ('server_config', 'host'),
            'CALC_SERVER_PORT': ('server_config', 'port'),
            'CALC_MAX_CACHE_SIZE': ('server_config', 'max_cache_size'),
            'CALC_PRECISION': ('server_config', 'precision'),
            'CALC_ENABLE_METRICS': ('server_config', 'enable_metrics'),
            'CALC_ENABLE_HISTORY': ('server_config', 'enable_history'),
            'CALC_MAX_HISTORY_SIZE': ('server_config', 'max_history_size'),
            
            # 安全配置
            'CALC_MAX_EXPR_LENGTH': ('security_config', 'max_expression_length'),
            'CALC_MAX_RECURSION_DEPTH': ('security_config', 'max_recursion_depth'),
            'CALC_TIMEOUT_SECONDS': ('security_config', 'timeout_seconds'),
            'CALC_ENABLE_FUNCTION_WHITELIST': ('security_config', 'enable_function_whitelist'),
            
            # 日志配置
            'CALC_LOG_LEVEL': ('logging_config', 'level'),
            'CALC_LOG_FILE': ('logging_config', 'file_path'),
            'CALC_LOG_MAX_SIZE': ('logging_config', 'max_file_size'),
            'CALC_LOG_BACKUP_COUNT': ('logging_config', 'backup_count'),
            'CALC_LOG_ENABLE_CONSOLE': ('logging_config', 'enable_console'),
            'CALC_LOG_ENABLE_FILE': ('logging_config', 'enable_file'),
        }
        
        for env_var, (config_obj, attr) in env_mappings.items():
            value = os.getenv(env_var)
            if value is not None:
                config_obj = getattr(self, config_obj)
                
                # 类型转换
                current_value = getattr(config_obj, attr)
                if isinstance(current_value, bool):
                    value = value.lower() in ('true', '1', 'yes', 'on')
                elif isinstance(current_value, int):
                    value = int(value)
                elif isinstance(current_value, float):
                    value = float(value)
                
                setattr(config_obj, attr, value)
    
    def save_config(self, file_path: Optional[str] = None):
        """保存配置到文件"""
        file_path = file_path or self.config_file or "config.json"
        
        config_data = {
            'server': asdict(self.server_config),
            'security': asdict(self.security_config),
            'logging': asdict(self.logging_config)
        }
        
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                if file_path.endswith('.json'):
                    json.dump(config_data, f, indent=2, ensure_ascii=False)
                elif file_path.endswith(('.yaml', '.yml')):
                    import yaml
                    yaml.dump(config_data, f, default_flow_style=False, allow_unicode=True)
                    
        except Exception as e:
            print(f"保存配置文件失败: {e}")
    
    def get_all_config(self) -> Dict[str, Any]:
        """获取所有配置"""
        return {
            'server': asdict(self.server_config),
            'security': asdict(self.security_config),
            'logging': asdict(self.logging_config)
        }
    
    def update_config(self, config_type: str, **kwargs):
        """更新配置"""
        if config_type == 'server':
            config_obj = self.server_config
        elif config_type == 'security':
            config_obj = self.security_config
        elif config_type == 'logging':
            config_obj = self.logging_config
        else:
            raise ValueError(f"未知的配置类型: {config_type}")
        
        for key, value in kwargs.items():
            if hasattr(config_obj, key):
                setattr(config_obj, key, value)
            else:
                raise ValueError(f"未知的配置项: {key}")
    
    def validate_config(self) -> Dict[str, Any]:
        """验证配置"""
        errors = []
        warnings = []
        
        # 验证服务器配置
        if self.server_config.port < 1 or self.server_config.port > 65535:
            errors.append("端口号必须在1-65535之间")
        
        if self.server_config.max_cache_size < 0:
            errors.append("缓存大小不能为负数")
        
        if self.server_config.precision < 1 or self.server_config.precision > 100:
            warnings.append("精度建议设置在1-100之间")
        
        # 验证安全配置
        if self.security_config.max_expression_length < 10:
            warnings.append("表达式最大长度过小，可能影响正常使用")
        
        if self.security_config.timeout_seconds < 1:
            errors.append("超时时间不能小于1秒")
        
        # 验证日志配置
        if self.logging_config.level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
            errors.append("无效的日志级别")
        
        return {
            'valid': len(errors) == 0,
            'errors': errors,
            'warnings': warnings
        }

# 全局配置实例
config_manager = ConfigManager()